package tsVRPTW;

import static tsVRPTW.Parameter.*;

/**
 * check(RouteType R[])函数，对产生的解进行检验，检验解R[]是否满足容量约束和时间窗约束，并修改Alpha与Beta的值。
 * UpdateSubT(RouteType r)函数。更新路径r的时间窗总违反量
 * Calculation(RouteType R[])。计算评价函数
 * @author cxd15
 */
public class EvaluateRoute {

	/**
	 * 检验解R[]是否满足容量约束和时间窗约束，并修改Alpha与Beta的值。
	 * 
	 * @param R[] 所有路径的数组
	 * @return true or false
	 */
	public static boolean Check(RouteType R[]) {
		double Q = 0; // 所有路径的超出的总的路径容量约束量
		double T = 0; // 所有路径的超出的总时间窗约束量

//		检查是否满足容量约束（遍历每条路线，获取总负载违反量）
		for (int i = 1; i <= VehicleNumber; i++) { // 车辆从1开始数
//			如果i路径中的节点大于2（即该路径中除了首位节点，还有别的节点）；i路径中的总载量大于最大容量
			if (R[i].V.size() > 2 && R[i].Load > Capacity) {
				Q = Q + (R[i].Load - Capacity); // 更新总违反约束容量
			}
		}

//		检查是否满足时间窗约束量（获取总的时间窗违反量）
		for (int i = 1; i <= VehicleNumber; i++) {
			T += R[i].SubT;
		}

//		更新惩罚系数Alpha和Beta值（新路径满足条件，惩罚系数减小；新路径不满足约束，惩罚系数增大）
//		惩罚系数不能无限增大或减小，必须有上下限 (0.001, 2000)
		if (Q == 0 && Alpha >= 0.001) { // 若是新路径的负载量未超出约束，惩罚系数减小
			Alpha = Alpha / (1 + Sita);
		} else if (Q != 0 && Alpha <= 2000) { // 若是新路径的负载量超出约束，惩罚系数增大
			Alpha = Alpha * (1 + Alpha);
		}

		if (T == 0 && Beta >= 0.001) { // 若是新路径未违反时间窗约束，惩罚系数减小
			Beta /= (1 + Sita);
		} else if (T != 0 && Beta <= 2000) { // 若是新路径违反时间窗约束，惩罚系数增大
			Beta *= (1 + Beta);
		}

		if (T == 0 && Q == 0) { // 如果两个约束都满足，返回true
			return true;
		} else {
			return false;
		}
	}

	// 更新路径r上的，时间窗总违反量
	public static void UpdateSubT(RouteType r) {
		double ArriveTime = 0; // 到达时间，表示车辆开始为当前结点服务的时间（此时表示在出发仓库的时间点）
		for (int i = 1; i < r.V.size(); i++) { // 遍历r路径中的每一个节点，从第二个结点开始，因为第一个节点是仓库
			// 计算到达当前节点的时间
			ArriveTime = ArriveTime // 到达上一节点的时间
					+ r.V.get(i - 1).Service // 在上一节点的服务时间
					+ Graph[r.V.get(i - 1).Number][r.V.get(i).Number]; // 上一节点到当前节点路程花费的时间

			if (ArriveTime > r.V.get(i).End) { // 如果到达时间晚于时间窗结束时间
				r.SubT = r.SubT + ArriveTime - r.V.get(i).End; // 更新r路径总约束
			} else if (ArriveTime < r.V.get(i).Begin) { // 车辆到了，时间窗还没开始
				ArriveTime = r.V.get(i).Begin; // 车辆需要等待
			}
		}
	}

	/**
	 * 计算评价函数（f(R) = D + Alpha * Q + Beta * T） D路径总长度（优化目标），Q超出容量约束总量，T超出时间窗约束总量
	 * D表示路径的总长度，由于车辆的速度一定，所以路径长度可以代表时长
	 */
	public static double Calculation(RouteType R[]) {
		double D = 0;
		double Q = 0;
		double T = 0;

//		计算D
		for (int i = 1; i <= VehicleNumber; i++) {
			D += R[i].Dis;
//			if (D<0) {
//				System.out.println(D+"D为负！！！");
//			}
		}

//		计算Q
		for (int i = 1; i <= VehicleNumber; i++) {
			if (R[i].V.size() > 2 && R[i].Load > Capacity) {
				Q = Q + (R[i].Load - Capacity);
			}
		}

//		计算T
		for (int i = 1; i <= VehicleNumber; i++) {
			T += R[i].SubT;
		}

		return (D + Alpha * Q + Beta * T);
	}
}